#include "StdAfx.h"
//@author A0083881W
#include "Validator.h";

enum Validator::FREQUENCY_TYPE;

bool Validator::isValidCommand(string command){
	if(!isLowerCase(command))
		command = toLowerCase(command);

    if(command == "add" || command =="delete" || command== "show"||command== "edit"
       || command== "search"||command== "clear" ||command=="done" ||command=="undone"
       ||command== "postpone"||command== "undo"||command=="help" ||command== "exit")
	   return true;
	else
		return false;

};

bool Validator::isValidKeyword(string keyword){
         if(!isLowerCase(keyword))
             keyword = toLowerCase(keyword);

        if(keyword == "-name" || keyword == "-date" || keyword =="-starts" 
			|| keyword== "-ends" ||keyword== "-impt"|| keyword== "-unimpt"
			||keyword== "-repeat" ||keyword== "-detail")
                return true;
        else
                return false;

};

bool Validator::isValidFrequency(string frequency){
	if(frequency == "weekly" || frequency == "monthly")
		return true;
	else
		return false;
};

bool Validator::isEmptyString(string sentence){

        if(sentence.size()==0)
                return true;
        else 
                return false;
};

bool Validator::isEmptyTaskList(vector<Task*> & taskList){
        if(taskList.size()==0)
                return true;
        else
                return false;
};

//the function checks if every character if its a digit
// its assumed that any input with everycharacter is a digit, that input is cosidered an integer. 
//else it is a string.
bool Validator::isInt(string input){

        int check =0;
        int space=0;
		if(isEmptyString(input))
			return false;
		else{
			for(int i=0; i < input.size(); i ++){
				if(isdigit(input[i]))
					check +=1;
				if(isspace(input[i]))
					space +=1;
			}
			if(check== input.size()-space)
				return true;
			else 
				return false;
		}

       
};

bool Validator::isLeapYear(string year){
        int leapyear;
        //precondition: year contains numbers
        assert (isInt(year));
        assert (year.size()>0);

		leapyear= atoi(year.c_str());
        //postcondition: leapyear is now of integer data type
        assert (leapyear%2 >= 0);

        if(!(leapyear%4) && (leapyear%100) || !(leapyear%400))
                return true;
        else
                return false;

};

bool Validator::isValidDate(string& date){

		if(date == "")
			return false;
        date=makeProperDateFormat(date);
        tokenizeDate(date);
        changeStringToInt();

        int day= getDay();
        int month= getMonth();
        string year= getYear();

        if((isValidDay(day,month, year)) && (isValidMonth(day,month,year)) && (isValidYear(year))){
			date=makeProperDayFormat(date);
            date=makeProperMonthFormat(date);
			return true;
		}
                
        else
                        return false;
                
};

bool Validator:: isValidPostponeDate(string &deadline_date, string &postponed_date){

	if(deadline_date == "")
		deadline_date = getCurrentDate();

	deadline_date=makeProperDateFormat(deadline_date);
	postponed_date=makeProperDateFormat(postponed_date);

	tokenizeDate(deadline_date);
	changeStringToInt();
	int deadline_day = getDay();
	int deadline_month = getMonth();
	int deadline_year = atoi(getYear().c_str());

	tokenizeDate(postponed_date);
	changeStringToInt();
	int postpone_day= getDay();
	int postpone_month= getMonth();
	int postpone_year= atoi(getYear().c_str());

	if(postpone_year > deadline_year)
		return true;
	if(postpone_year< deadline_year)
		return false;
	if(postpone_year== deadline_year){
		if(postpone_month > deadline_month)
			return true;
		if(postpone_month < deadline_month)
			return false;
		if(postpone_month == deadline_month){
			if(postpone_day > deadline_day)
				return true;
			if(postpone_day <= deadline_day)
				return false;
		}
	}

	else 
		return false;
};

// vector is used as there maybe more than 1 occurance of the same taskname in the storage.
bool Validator::isValidTask(string taskname, vector<Task*> & taskList){
                 
                 clearTempVector();
                 assert (tempVector.size()==0);

        for(int i =0; i < taskList.size(); i ++){
			
			if (taskname == taskList[i]->getName())
                        tempVector.push_back(taskname);
        }
                if (!tempVector.empty())
                        return true;
                else 
                        return false;
    
};

//changes will be made especially when the search function is implemented.
bool Validator::isValidTaskNumber(int tasknumber, vector<Task*> & taskList){
        if(tasknumber < taskList.size())
                return true;
        else
                return false;
};


string Validator::toLowerCase(string input){
        for(int i=0; i< input.size(); i++){
                input[i]=tolower(input[i]);
        }

        return input;
};

int Validator::getDay(){
        int day = dateVector[0];
        return day;
};

int Validator::getMonth(){
        int month = dateVector[1];
        return month;
};

string Validator::getYear(){
        string year= tempVector[2];
               
        return year;
};

bool Validator::isValidMonth(int day, int month,string year){
        int validyear;

        if(isInt(year))
                validyear= atoi(year.c_str());
		
		if(isValidYear(year) && month > getCurrentMonth())
			return true;
		if(isValidYear(year) && month == getCurrentMonth() && day >= getCurrentDay())
			return true;
		if( validyear > getCurrentYear())
			return true;
		else
			return false;
	
};

bool Validator::isValidDay(int day, int month, string year){
        switch (month){
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
                
                if(day <= 31  && day !=0)
                                        return true;
                                else
                                        return false;
                                break;
        
        case 2:{
        
                if(isLeapYear(year)){
                                        if(day<= 29 && day !=0)
                        return true;
                                        else 
                                                return false;   
                }
                else{
                       if( day <= 28 && day != 0)
                        return true;
                                           else
                                                   return false;
                }
                break;
                           }        
        case 4:
        case 6:
        case 9:
        case 11:
               
               if( day <= 30 && day!= 0)
                                   return true;
                           else
                                   return false;
               break;
                
        default:
                return false;

        }
};

bool Validator::isValidYear(string year){
        int validyear;

        if( isInt(year))
                 validyear= atoi(year.c_str());

        if(validyear>= getCurrentYear() && year.size() ==4)
                return true;
        else
                return false;
      
};

// the date comes in the form of a string
// this hels to spilt the date into day, month and year.
void Validator::tokenizeDate(string date){
        istringstream tokenizethedate(date);
        string token;

        clearVectors();
        assert(tempVector.size()==0);
        assert(dateVector.size()==0);
        
        while(!tokenizethedate.eof()){
			getline(tokenizethedate, token,'/');
            tempVector.push_back(token);
        }
        
};

// this function converts the  split string date into integers
void Validator::changeStringToInt(){

for(int i=0; i < tempVector.size(); i++){
        string convertstring = tempVector[i];
        int converted = atoi(convertstring.c_str());
        dateVector.push_back(converted);
}

//post condition
assert(dateVector.size() != 0);
};
 bool Validator::isValidTaskName(string taskname){
        int check=0;

		if(isEmptyString(taskname))
			return true;
		else{
			for(int i=0; i<taskname.size(); i++){
			if(isalpha(taskname[i])||isdigit(taskname[i]))
				check+=1;
			}
		if(check>0)
			return true;
		else
			return false;
		}
 };

 string Validator::makeProperDayFormat(string date){
	 
	 if( isdigit(date[0]) && isdigit(date[1]) && date[2]=='/')
		 return date;
	 else if(isdigit(date[0]) && date[1]=='/'){
		 date= date.insert(0, "0");
		 return date;
	 }
 };

 string Validator::makeProperDateFormat(string date){
        string newdate;
        int slash=0;

        for(int i=0; i <date.size(); i++){
			if(date[i]=='/')
				slash+= 1;
             else
				 slash+= 0;
		}

        if(slash==2)
                return date;
        if(slash==0){

                        assert(date.size() > 0);
                        newdate= addMonthAndYear(date);
        }
        if(slash==1){
                newdate=addYear(date);
                }

                

        return newdate;
 };

 //tm_mon tells you the month from 0:Jan to 11:Dec
string Validator::addMonthAndYear(string date){
        string month;
        stringstream ss;

        int currentmonth= getCurrentMonth();

        ss<< currentmonth;
        month= ss.str();

        date=addStringToString(date, month);
        date=addYear(date);
                
        return date;
 };

//tm_year gives u the number of years since 1900
 string Validator::addYear(string date){
        string year;
        stringstream ss;
         
        int currentyear= getCurrentYear();

        ss<< currentyear;
        year= ss.str();
        date=addStringToString(date, year);

        return date;
 };

string Validator::formatTime(string time)
 {
         string formattedTime = time;

        if(formattedTime.size() == 1)
                formattedTime = "0"+formattedTime+"00";

        if(formattedTime.size() == 2)
                formattedTime.append("00");
        
        if(formattedTime.size() == 3)
                formattedTime = "0"+formattedTime;

        return formattedTime;
 }

 bool Validator::isValidTimeRange(string &time)
 {
    int time_hour_int,time_min_int;
    string hour,min;
    bool result = true;

	if(time.size() > 4)
		result = false;

    time = formatTime(time);
    hour= time.substr(0,2);
    min= time.substr(2,2);

    time_hour_int= atoi(hour.c_str());
    time_min_int= atoi(min.c_str());

    if(time_hour_int < 00 || time_hour_int > 23 || 
		time_min_int < 00 || time_min_int > 59)
		result = false;

	return result;
 }

 bool Validator::isValidTimeDeadline(string time, string date){
    int time_hour_int,time_min_int;
    string hour,min;
	bool result = false;

    hour= time.substr(0,2);
    min= time.substr(2,2);

    time_hour_int= atoi(hour.c_str());
    time_min_int= atoi(min.c_str());

    if(getCurrentDate() == date)
    {
        if(time_hour_int == getCurrentHour())
        {
                if(time_min_int > getCurrentMinute())
                        result = true;
        }
        else if(time_hour_int > getCurrentHour())
                result = true;
        else
                result = false;
    }
    else
        result = true;

	return result;
 };

 int Validator::getCurrentMonth(){
         
          struct tm * current_timeinfo;
     
          current_timeinfo = &getCurrentTimeInfo();

          int month =current_timeinfo->tm_mon+ 1;

          assert (month>0 && month<13);
          return month;
 };

 int Validator::getCurrentYear(){
         struct tm * current_timeinfo;
     
         current_timeinfo = &getCurrentTimeInfo();

         int year = (current_timeinfo->tm_year + 1900);

         assert ( year>=2012);
         return year;
 };

 int Validator::getCurrentHour(){
          struct tm * current_timeinfo;
     
          current_timeinfo = &getCurrentTimeInfo();

          int hour = current_timeinfo->tm_hour; 

          assert (hour >= 00 && hour < 24);
          return hour;
 };

 int Validator::getCurrentMinute(){
          struct tm * current_timeinfo;
     
          current_timeinfo = &getCurrentTimeInfo();

          int min = current_timeinfo->tm_min;

          assert (min >= 0 && min <60);
          return min;
 };

 int Validator::getCurrentDay(){
   
      struct tm * current_timeinfo;
          
      current_timeinfo= &getCurrentTimeInfo();
         
      int day =current_timeinfo->tm_mday;
	  
      assert (day >0 && day <= 31);
      return day;
         
 };

 string Validator::addStringToString(string originalstring, string addstring){
        
         string newstring=originalstring.append("/");
         newstring=newstring.append(addstring);

         assert (newstring.size()> originalstring.size());

         return newstring;
 };

 bool Validator::isFileEmpty(fstream &storeFile){

         if(storeFile.is_open()){
                 if(storeFile.peek() == std::ifstream::traits_type::eof())
                         return true;
                 else 
                         return false;
         }
         else
                 return false;

 };

 bool Validator::isLowerCase(string input){
         int check=0;
         int space=0;

         for(int i=0; i< input.size(); i++){
                 if(islower(input[i]))
                         check++;
                 if(isspace(input[i]))
                         space++;
         }

         if(check>= input.size()-space)
                 return true;
         else
                 return false;

 };

 void Validator:: clearVectors(){
         if(!tempVector.empty())
                         tempVector.erase(tempVector.begin(),tempVector.end());
        if(!dateVector.empty())
                        dateVector.erase(dateVector.begin(), dateVector.end());
 };

 void Validator::clearTempVector(){
          if(!tempVector.empty())
                         tempVector.erase(tempVector.begin(),tempVector.end());

 };

 bool Validator::isNotPastDeadLine(string date){

        tokenizeDate(date);
        changeStringToInt();

		if(getCurrentDate() == date)
			return true;
		else{

			if (!tempVector.empty())
			{
                string getyear= getYear();
                int year;
        
                if(isInt(getYear()))
                         year= atoi(getyear.c_str());
                assert (year%2 >=0 );

                if(year> getCurrentYear())
                        return true;
                if(year< getCurrentYear())
                        return false;

				else{
					if(getMonth()> getCurrentMonth())
                        return true;
					if(getMonth()< getCurrentMonth())
                        return false;
					else{
						if(getDay()>= getCurrentDay())
							return true;
                        else
							return false;
					}
				}
			}
			else
				return false;
		}
 
 };

 string Validator:: getCurrentDate(){
         
         string currentdate;
         stringstream ss;

         ss<< getCurrentDay();
         currentdate = ss.str();

         currentdate= addMonthAndYear(currentdate);
         currentdate= makeProperDayFormat(currentdate);

         return currentdate;

 };

 string Validator::makeProperMonthFormat(string date){

         if(date[4] =='/'&& isdigit(date[3]) && isdigit(date[5])){
                 date=date.insert(3,"0");
                 return date;
         }
         else
                 return date;
                 
 };

 tm Validator:: getCurrentTimeInfo(){
	   time_t rawtime;
	  struct tm * timeinfo;
          
      time ( &rawtime );
      timeinfo = localtime ( &rawtime );

	  return *timeinfo;

 };

 Validator::FREQUENCY_TYPE Validator::determineFrequencyType(string frequency){
	 
	 if(!isLowerCase(frequency))
		 frequency = toLowerCase(frequency);
	 
	 if(frequency == "weekly")
		 return FREQUENCY_TYPE::WEEKLY;
	 if(frequency == "monthly")
		 return FREQUENCY_TYPE::MONTHLY;

 };

vector<string> Validator::repeatMode(string date, string frequency){
	vector<string>repeatVector;

	tokenizeDate(date);
	changeStringToInt();
	int day = getDay();
	int month = getMonth();
	string year = getYear();
	
	 if(!repeatVector.empty())
		 repeatVector.erase(repeatVector.begin(),repeatVector.end());

	 FREQUENCY_TYPE frequency_type= determineFrequencyType(frequency);

	 switch(frequency_type){
	 case 0: 
		  repeatVector = getWeeklyDates(day, month, year);
		  break;
	 case 1:
		  repeatVector = getMonthlyDates(day, month, year);
		  break;
	 default:
		 repeatVector.push_back("ERROR");
		 break;
	 }

	 return repeatVector;
 };

vector<string> Validator::getWeeklyDates(int day, int month, string year){

	int currentmonth = month;
	string date_day, date_month, date;
	vector<string> weekVector;

	while( currentmonth == month){
		day+= 7;
		if(isValidDay(day,month,year)){

			date_day = changeIntToString(day);
			date_month = changeIntToString(month);
			
			date= date_day + "/" + date_month +"/"+ year;
			date= makeProperDayFormat(date);
			date= makeProperMonthFormat(date);

			weekVector.push_back(date);
		}
		else
			month++;
	}

	return weekVector;

};

vector <string> Validator ::getMonthlyDates (int day, int month, string year){

	int currentyear= atoi(year.c_str());
	int givenyear = atoi(year.c_str());

	string date_day, date_month,  date;
	vector<string> monthlyVector;

	while(currentyear == givenyear){
		month++;
	if(month<= 12){

		date_day=changeIntToString(day);
		date_month=changeIntToString(month);

		date= date_day + "/" + date_month + "/" + year;
		date= makeProperDayFormat(date);
		date= makeProperMonthFormat(date);

		monthlyVector.push_back(date);
	}
	else
		currentyear++;
	}

	return monthlyVector;
};

string Validator ::changeIntToString( int integer){

	stringstream ss;
	ss.str(string());
	string changed;

	ss<< integer;
	changed = ss.str();

	return changed;

};

string Validator::getMonthOfYear(string date){
        tokenizeDate(date);
		changeStringToInt();
        int month = getMonth();
        string what_month = getMonthString(month);

        return what_month;
};

string Validator::whenNoMoreDate(string date, string frequency){
        FREQUENCY_TYPE frequent;
        string month, year;

		frequent = determineFrequencyType(frequency);

        switch(frequent){
        case 0:{
                month = getMonthOfYear(date);
                return month;
                   }
        case 1:{
                year = getRepeatYear(date);
                return year;
                   }
        default:
                return "ERROR";
        }
};

string Validator::getMonthString(int month){

        switch (month){
        case 1:
                return "January";
        case 2:
                return "February";
        case 3:
                return "March";
        case 4: 
                return "April";
        case 5:
                return "May";
        case 6:
                return "June";
        case 7:
                return "July";
        case 8:
                return "August";
        case 9:
                return "September";
        case 10:
                return "October";
        case 11:
                return "November";
        case 12:
                return "December";
        default:
                return "ERROR";
        }
};

string Validator:: getRepeatYear(string date){
        tokenizeDate(date);
        string year = getYear();

        return year;
};

string Validator::noFurther(string frequency)
{
		FREQUENCY_TYPE frequent;

		frequent = determineFrequencyType(frequency);

        switch(frequent){
        case 0:{
                return "weeks";
                   }
        case 1:{
                return "months";
                   }
        default:
                return "ERROR";
        }
};

string Validator::noFurtherIn(string frequency)
{
		FREQUENCY_TYPE frequent;

		frequent = determineFrequencyType(frequency);

        switch(frequent){
        case 0:{
                return "month";
                   }
        case 1:{
                return "year";
                   }
        default:
                return "ERROR";
        }
}